<!--
 * @Description: 呆龙封装的表格组件
 * @Version: 1.0
 * @Author: 呆龙
 * @Date: 2023-08-26 12:17:35
 * @LastEditTime: 2023-09-25 08:51:27
 * @LastEditors: 呆龙
 * 需要传的参数 具体类型看props ?号代表可选
 * 1.tableData: 表格数据
 * 2.columns: 表格列
 * 3.rowKey: 表格行key
 * 4.loading: 表格是否显示加载中
 * 5.current: 表格当前页 // 已废弃
 * 6.total: 表格数据总数 // 已废弃
 * 7.useExpand: 是否使用扩展页面
 * 8.usePrint: 是否使用打印功能
 * 8.1 必须要传入 printData 就是所有的数据 不能是分页的
 * 9.printTitle: 是否自定义打印的表格标题
 * 10.useExcel: 是否使用excel表格导出功能
 * 11.useNumber: 是否自动使用序号 可以设置是否为连续序号
 * 可以监听的函数
 * 1.changePage: 表格翻页时触发  回参 page为页码 size 为每页显示的条数
 * 2.reload: 点击刷新按钮的时候触发的事件 回参 current为当前页 size 为每页显示的条数
 * 3.expanded: 表格扩展页面展开时触发  回参record该行的数据
-->
<template>
  <a-card style="margin-top: 10px" class="tableCard" :bordered="cardBorder">
    <div class="soltBox">
      <slot name="header"></slot>
      <a-button
        shape="circle"
        size="middle"
        style="margin-right: 10px"
        @click="printTable"
      >
        <printer-outlined />
      </a-button>
      <a-button
        shape="circle"
        size="middle"
        style="margin-right: 10px"
        @click="saveExcel"
      >
        <download-outlined />
      </a-button>
      <a-button
        shape="circle"
        size="middle"
        style="margin-right: 10px"
        @click="reload"
      >
        <sync-outlined />
      </a-button>
      <a-dropdown v-model:visible="state.visible" :trigger="['click']">
        <a-button shape="circle" size="middle">
          <table-outlined />
        </a-button>
        <template #overlay>
          <a-card style="width: 185px">
            <div style="margin: 5px 0; padding-left: 10px">
              <a-checkbox
                v-model:checked="state.checkedAll"
                @change="
                  columns.forEach(item => (item.isShow = state.checkedAll))
                "
                >全部</a-checkbox
              >
            </div>
            <a-menu
              style="
                height: 250px;
                overflow-y: scroll;
                border-top: 1px solid #dadce0;
                border-bottom: 1px solid #dadce0;
              "
            >
              <a-menu-item v-for="item in state.plainOptions" :key="item">
                <a-checkbox v-model:checked="item.isShow">{{
                  item.title
                }}</a-checkbox>
              </a-menu-item>
            </a-menu>
            <a-button style="width: 50%; border: none" @click="changeColumns"
              >确认</a-button
            >
            <a-button
              style="width: 50%; border: none"
              @click="changeColumns(true)"
              >还原</a-button
            >
          </a-card>
        </template>
      </a-dropdown>
    </div>
    <a-table
      :columns="state.tableColumns"
      :pagination="pagination"
      :data-source="tableData"
      :rowKey="rowKey"
      :loading="loading"
      @expand="viewDetails"
      :expandedRowKeys="expandedRowKeys"
      :bordered="useBorder"
      :scroll="scroll"
      :row-selection="
        !useSelect
          ? null
          : {
              selectedRowKeys: selectTable.selectedRowKeys,
              onChange: onSelectChange,
              hideSelectAll: isSole,
            }
      "
    >
      <template #bodyCell="{ text, record, index, column }">
        <template v-if="column.dataIndex === 'DaiNumber'">
          {{ (pagination.current! - 1) * pagination.pageSize! + index + 1 }}
        </template>
        <template v-if="column.copyable">
          <div class="copyBox">
            <a-tooltip :title="text" v-if="column.tooltip">
              <div :class="column.ellipsis ? 'ellipsis' : ''">{{ text }}</div>
            </a-tooltip>
            <div v-else :class="column.ellipsis ? 'ellipsis' : ''">
              {{ text }}
            </div>
            <copy-outlined
              @click="copy(text)"
              class="copyIcon"
              style="color: #1890ff; cursor: pointer; margin-left: 3px"
            />
          </div>
        </template>
        <template v-else-if="column.tooltip">
          <a-tooltip :title="text">
            <div
              :class="column.ellipsis ? 'ellipsis' : ''"
              style="cursor: pointer"
            >
              {{ text }}
            </div>
          </a-tooltip>
        </template>
        <slot
          name="Column"
          :text="text"
          :record="record"
          :index="index"
          :column="column"
        >
        </slot>
      </template>
      <template
        #expandedRowRender="{ text, record, index, column }"
        v-if="useExpand"
      >
        <slot
          name="custom"
          :text="text"
          :record="record"
          :index="index"
          :column="column"
        ></slot>
      </template>
    </a-table>
  </a-card>
</template>

<script setup lang="ts">
// 引入打印的js
import printJS from "print-js";
// 引入excel的js 保存文件的js
import { Workbook } from "exceljs";
import { saveAs } from "file-saver";
import { forEach, cloneDeep } from "lodash";
// antd的图标
// PrinterFilled
import {
  SyncOutlined,
  TableOutlined,
  DownloadOutlined,
  PrinterOutlined,
  CopyOutlined,
} from "@ant-design/icons-vue";
import { message } from "ant-design-vue";
import type { PaginationProps } from "ant-design-vue";
import { ref, reactive, watch, onMounted } from "vue";
import { Columns, ExcelReset } from "./index"; // 列的类型
// 引入复制插件vue-ues
import { useClipboard } from "@vueuse/core";
const { copy, copied } = useClipboard();
interface Props {
  // 表格数据
  tableData: any[];
  // 表格列
  columns: Columns[];
  // 表格的rowKey
  rowKey?: string;
  // 表格是否显示加载中
  loading?: boolean;
  // 是否使用扩展页面
  useExpand?: boolean;
  // 是否使用打印功能
  usePrint?: boolean;
  // 自定义打印的表格标题
  printTitle?: string;
  // 是否使用excel表格功能
  useExcel?: boolean;
  // 打印和excel所有的数据
  printData?: any[];
  //是否使用序号
  useNumber?: boolean;
  //是否固定序号
  numberFixed?: boolean;
  // 分页的数据
  pagination?: PaginationProps;
  // 是否开启多选列操作
  useSelect?: boolean;
  // 多选列是否唯一
  isSole?: boolean;
  // 是否使用边框
  useBorder?: boolean;
  // 滚动配置
  scroll?: object | null;
  // 是否需要卡片边框
  cardBorder?: boolean;
}
const props = withDefaults(defineProps<Props>(), {
  useExpand: false,
  usePrint: false,
  printTitle: "表格",
  useExcel: false,
  useNumber: false,
  useAction: false,
  rowKey: "id",
  scroll: null,
  isSole: false,
  cardBorder: true,
});
// 定义emit
const emit = defineEmits<{
  // 点击刷新的时候触发的事件 current为当前页 size 为每页显示的条数
  (e: "reload", current: number, size: number): void;
  // 点击+号扩展内容发生    record该行的数据
  (e: "expanded", record: any): void;
  // 点击多选框后触发的时候  传输的值为一个数组 数组里面包含了所有选中的值
  (e: "select", keyArr: string[], itemArr?: any[]): void;
}>();
onMounted(() => {
  if (props.useNumber) {
    state.tableColumns.unshift({
      title: "序号",
      dataIndex: "DaiNumber",
      align: "center",
      isShow: true,
      fixed: props.numberFixed ? "left" : "",
    });
    state.plainOptions.unshift({
      title: "序号",
      dataIndex: "DaiNumber",
      align: "center",
      isShow: true,
      fixed: props.numberFixed ? "left" : "",
    });
  }
  if (props.pagination) {
    pagination.value = {
      ...pagination.value,
      ...props.pagination!,
    };
  }
  changeColumns();
});
/**
 * 当传递的是分页配置的时候监听传递的分页配置 即使更新表格的分页数据
 */
watch(
  () => [props.pagination],
  () => {
    pagination.value = {
      ...pagination.value,
      ...props.pagination!,
    };
  },
  {
    deep: true,
  }
);
// 表格的页码数据
const pagination = ref<PaginationProps>({
  // 当前页
  current: 1,
  // 当前页的个数
  pageSize: 10,
  // 总数
  total: 10,
});
/**
 * 表格的头部是否显示选择框 - 多选列功能
 * selectTable 多选列的数据 根据rowkey 字符串数组
 * onSelectChange 点击复选框后触发的事件
 */
const selectTable = reactive({
  selectedRowKeys: [] as any[],
});
const onSelectChange = (selectedRowKeys: any[], selectedRows: any[]) => {
  if (props.isSole === true) {
    let key = selectedRowKeys[selectedRowKeys.length - 1];
    selectTable.selectedRowKeys = [key];
    emit("select", selectTable.selectedRowKeys);
  } else {
    selectTable.selectedRowKeys = selectedRowKeys;
    emit("select", selectTable.selectedRowKeys, selectedRows);
  }
};
// 列表筛选的状态数据存储信息
const state = reactive({
  // 是否全选
  checkedAll: true,
  // 是否显示
  visible: false,
  // 列选中的数据 用于展示或隐藏某个列
  plainOptions: [...props.columns],
  // 表格的列的数据
  tableColumns: [...props.columns],
});
// 控制展开行的数据 不重要
const expandedRowKeys = ref<number[]>([]);
/**
 * 控制表格列的隐藏和显示  点击按钮后会更改列数据的isShow属性 再根据这个属性进行筛选列
 */
const changeColumns = (reset?: boolean) => {
  state.visible = false;
  if (reset === true) {
    state.plainOptions.forEach(item => (item.isShow = state.checkedAll));
    state.tableColumns = props.columns;
  } else {
    state.tableColumns = state.plainOptions.filter(item => item.isShow);
  }
};
// 点击刷新按钮后触发的刷新事件
const reload = () => {
  emit("reload", pagination.value.current!, 10);
};
/**
 * 点击某条列表+号 展示列表的详细数据 里面的dom由 custom 插槽传输
 */
const viewDetails = (isOpen: any, record: any) => {
  if (isOpen) {
    expandedRowKeys.value[0] = record.id;
    emit("expanded", record);
  } else {
    expandedRowKeys.value = [];
  }
};
/**
 * 保存为excel的数据的函数
 */
const saveExcel = () => {
  const DEFAULT_COLUMN_WIDTH = 20;
  const reset = [] as ExcelReset[];
  console.log("state.tableColumns", state.tableColumns);
  const excelCol = state.tableColumns.map(col => {
    if (col.excel) {
      reset.push({
        dataIndex: col.dataIndex as string,
        rule: new Map(Object.entries(col.excel)),
      });
      // console.log(col.excel);
    }
    const colData = {
      // 显示的 name
      header: col.title,
      // 用于数据匹配的 key
      key: col.dataIndex,
      // 列宽
      width: col.width ? col.width / 7 : DEFAULT_COLUMN_WIDTH,
      // 是否允许排序
      style: {
        alignment: {
          horizontal: "center",
          vertical: "middle",
        },
      },
    };
    return colData;
  });
  // 创建工作簿
  const workbook = new Workbook();
  // 添加sheet
  const worksheet = workbook.addWorksheet(props.printTitle);
  // 设置 sheet 的默认行高
  worksheet.properties.defaultRowHeight = 20;
  // 设置列
  worksheet.columns = excelCol as any;
  // 添加行
  worksheet.addRows(props.tableData);
  console.log(reset);
  const row = worksheet.getRows(2, pagination.value.defaultPageSize as number);
  forEach(reset, (reset: any) => {
    forEach(row, (item: any, index: number) => {
      if (!props.useNumber) {
        item.getCell("DaiNumber").value = index + 1;
      }
      if (typeof reset.rule.get("render") === "function") {
        console.log(item.getCell(reset.dataIndex).value);
        const data = reset.rule.get("render")(
          item.getCell(reset.dataIndex).value
        );
        console.log(data);
        item.getCell(reset.dataIndex).value = data;
        console.log(item.getCell(reset.dataIndex).value);
        return;
      } else {
        const data = item.getCell(reset.dataIndex).value;
        if (reset.rule.has(data)) {
          item.getCell(reset.dataIndex).value = reset.rule.get(data);
        }
      }
    });
  });
  // 获取文件流并保存
  workbook.xlsx.writeBuffer().then(data => {
    const blob = new Blob([data], { type: "" });
    console.log(blob);
    saveAs(blob, "Excel.xlsx");
  });
};
/**
 *
 */
const printTable = () => {
  // 表格的数据拷贝
  const data = reactive({
    dataSource: cloneDeep(props.tableData),
  });
  console.log(data.dataSource);

  const properties = [] as any[];
  const reset = [] as ExcelReset[];
  state.tableColumns.map(item => {
    if (item.excel) {
      reset.push({
        dataIndex: item.dataIndex as string,
        rule: new Map(Object.entries(item.excel)),
      });
    }
    properties.push({
      field: item.dataIndex,
      displayName: item.title,
      columnsSize: item.width + "px",
    });
  });
  if (reset.length !== 0) {
    reset.map((reset: ExcelReset) => {
      forEach(data.dataSource, (item: any, index: number) => {
        if (!props.useNumber) {
          item["DaiNumber"] = index + 1;
        }
        if (typeof reset.rule.get("render") === "function") {
          item[reset.dataIndex] = reset.rule.get("render")(
            item[reset.dataIndex]
          );
        } else {
          if (reset.rule.has(item[reset.dataIndex])) {
            item[reset.dataIndex] = reset.rule.get(item[reset.dataIndex]);
          }
        }
      });
    });
  }
  console.log(data.dataSource);
  printJS({
    printable: data.dataSource,
    properties,
    type: "json",
    header: props.printTitle,
    gridStyle:
      "font-weight: normal;border: 1px solid #000;text-align:center;padding:5px 0;", // 表格样式
    gridHeaderStyle:
      "padding:5px; font-weight: normal;border: 1px solid #000;text-align:center;padding:5px 0;", //表头样式
  });
};

watch(
  () => copied.value,
  (val: boolean) => {
    if (val) {
      message.success("复制成功");
    }
  }
);
</script>

<style scoped lang="less">
// 185
:deep(.ant-menu-item) {
  padding: 0;
  width: 175px;
  padding-left: 10px;
  margin-bottom: 0;
  height: 30px;
  line-height: 30px;
  .ant-checkbox-wrapper {
    width: 100%;
  }
}
.tableCard {
  :deep(.ant-card-body) {
    padding: 10px 15px;
  }
}
:deep(.ant-menu:not(.ant-menu-horizontal) .ant-menu-item-selected) {
  background-color: transparent;
}
.upDateRecord {
  display: flex;
  align-items: center;
  font-size: 15px;
  color: #1890ff;
}
.soltBox {
  width: 100%;
  display: flex;
  justify-content: flex-end;
  margin-bottom: 10px;
}

.ellipsis {
  max-width: calc(100% - 15px);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  cursor: pointer;
}
.copyBox {
  display: flex;
  align-items: center;
  justify-content: center;
  .copyIcon {
    float: right;
  }
}
</style>
